const Base = require('./base/base');

let vowels='aeiouy',
	consonants='bcdfghklmnprstvzx';

/**
 * @extends base
 */
module.exports = class extends Base {
	encodeAction(param){
		let b = param.text;

		let r, i, e, h;
		if (typeof(b) === 'string') {
			b = Buffer.from(b, 'utf8');
		} else if (! Buffer.isBuffer(b)) {
			throw new Error('Bad input');
		}
		for (r = 'x', h = 1, i = 0, e = b.length - 1; i < e; i += 2) {
			r += (vowels[(((b[i] >> 6) & 3) + h) % 6] +
				  consonants[(b[i] >> 2) & 15] +
				  vowels[(((b[i]) & 3) + Math.floor(h / 6)) % 6] +
				  consonants[(b[i + 1] >> 4) & 15] +
				  '-' +
				  consonants[b[i + 1] & 15]);
			h = ((h * 5) + (b[i] * 7) + b[i + 1]) % 36;
		}
		if (b.length & 1) {
			r += (vowels[(((b[i] >> 6) & 3) + h) % 6] +
				consonants[(b[i] >> 2) & 15] +
				vowels[(((b[i]) & 3) + Math.floor(h / 6)) % 6] +
				  'x');
		} else {
			r += (vowels[h % 6] +
				consonants[16] +
				vowels[Math.floor(h / 6)] +
				  'x');
		}
	 return r;
	}
    _decode_tuple(src, pos){
        let tupl = [vowels.indexOf(src[0]), consonants.indexOf(src[1]), vowels.indexOf(src[2])];
        try {
            tupl.push(consonants.indexOf(src[3]));
            tupl.push('-');
            tupl.push(consonants.indexOf(src[5]));
		} catch(err) {
		}
        return tupl;
	}
    _decode_2way_byte(a1, a2, offset){
        if (a1 > 16) throw new Error(`corrupt string at offset ${offset}`);
        if (a2 > 16) throw new Error(`corrupt string at offset ${offset + 2}`);

        return a1 << 4 | a2
	}
    _decode_3way_byte(a1, a2, a3, offset, c){
        let high2 = (a1 - (c % 6) + 6) % 6

        if (high2 >= 4) throw new Error(`corrupt string at offset ${offset}`);
        if (a2 > 16) throw new Error(`corrupt string at offset ${offset + 1}`);

        let mid4 = a2,
        	low2 = (a3 - (Math.floor(c / 6) % 6) + 6) % 6;

        if (low2 >= 4) throw new Error(`corrupt string at offset ${offset + 2}`);

		return high2 << 6 | mid4 << 2 | low2
	}
	// 解密算法根据python/bubblepy改编
	decodeAction(param){
		let src = param.text.slice(1,-1),
			c = 1,
			_src = [];
		for(let x=0;x<src.length;x+=6){_src.push(src.slice(x,x+6))}
		let out = [];
		for(let k in _src){
			let pos = k * 6,
				tup = this._decode_tuple(_src[k], pos);
			if (k === _src.length - 1) {
				if (tup[1] === 16) {
					if (tup[0] != c % 6) throw new Error(`corrupt string at offset ${pos} (checksum)`)
					if (tup[2] != Math.floor(c/6)) throw new Error(`corrupt string at offset ${pos+2} (checksum)`);
				}
				else {
					let byte = this._decode_3way_byte(tup[0], tup[1], tup[2], pos, c);
					out.push(byte);
				}
			}
			else {
				let byte1 = this._decode_3way_byte(tup[0], tup[1], tup[2], pos, c),
					byte2 = this._decode_2way_byte(tup[3], tup[5], pos);
				out.push(byte1);
				out.push(byte2);
				c = (c * 5 + byte1 * 7 + byte2) % 36;
			}
		}
		return Buffer.from(out.filter(z=>z!=-1)).toString();
	}
}